# -*- coding: utf-8 -*-
"""
用于客户端端的端口复用发送
将客户端发送到服务器的数据端口，全部发送到服务器的A端口
比如：
A游戏客户端需要向服务器A端口和B端口发送数据
那么该程序将抓包客户端数据包中向服务器发送的数据包，并整合A端口和B端口的数据，全部发送到服务器的A端口
"""
import configparser
import threading
import time

import psutil
import pyshark
from scapy.layers.inet import TCP, IP, UDP
from scapy.sendrecv import sniff
from frp import *
class ReadConfig:
    def __init__(self,ConfgPath:str):
        self.ConfgPath = ConfgPath
        self.classprint = "Server ReadConfig:"
        # 创建 ConfigParser 实例，用来解析 config.ini
        self.conf = configparser.ConfigParser()
        self.conf.read(ConfgPath)

    def getPrcessName(self):
        return self.conf.sections()

class PrcessTool:
    """
    进程工具，用于 进程的处理
    """
    def __init__(self):
        self.ProcessData=self.get_all_processes()

    def get_all_processes(self):
        """
        获取所有运行中的进程信息
        """
        processes = []
        for proc in psutil.process_iter(['pid', 'name', 'username']):
            try:
                processes.append(proc.info)
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                pass
        return processes

    def get_process_by_name(self,name):
        """
        根据进程名获取进程信息
        """
        for process in self.ProcessData:
            if process["name"] == name:
                return process
        return None

    def get_port_by_name_with_psutil(self, name):
        """
        使用 psutil 根据进程名获取进程端口（原始方法作为备选）
        """
        process = self.get_process_by_name(name)
        if process is None:
            return None

        try:
            # 获取进程的连接信息
            proc = psutil.Process(process["pid"])
            print("进程pid:", proc)
            connections = proc.net_connections()

            ports = []
            for conn in connections:
                if conn.status in [psutil.CONN_ESTABLISHED, psutil.CONN_LISTEN]:
                    port_info = {
                        'port': conn.laddr.port,
                        'local_address': f"{conn.laddr.ip}:{conn.laddr.port}",
                        'status': conn.status,
                        'foreign_address': f"{conn.raddr.ip}:{conn.raddr.port}" if conn.raddr else ''
                    }
                    ports.append(port_info)

            return ports if ports else None
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            return None

    def get_port_by_name(self, name):
        """
        根据进程名获取进程端口
        """

        ports = self.get_port_by_name_with_psutil(name)

        return ports

class NetTool:
    def __init__(self):
        self.IFACE= 'VMware Network Adapter VMnet8'          # ← 改成你本机要监听的接口
        #self.IFACE= 'Adapter for loopback traffic capture'          # ← 改成你本机要监听的接口
        self.port_list:list=[]
        self.cap_list:list=[]
        self.capture:pyshark.LiveCapture=None
        self.PCAP= 'C:\\Users\Lenovo\PyCharmMiscProject\数据\\'#保存的数据包
    def start_capture_by_port(self, port_list):
        """
        监听端口pyshark方法
        """
        self.port_list= port_list
        bpf = " or ".join(f"(tcp port {p} or udp port {p})" for p in self.port_list)
        self.capture = pyshark.LiveCapture(
            interface=self.IFACE,
            bpf_filter=bpf,  # Berkeley Packet Filter
            output_file=self.PCAP+f"{123}.pcap"
        )

    def frp_port_list(self,port_list):
        """
        frp端口列表
        """
        self.port_list= port_list
        for port in self.port_list:
            remothost="192.168.60.133"
            remoteport = 12345

            targethost="192.168.60.133"
            targetport = port
            print(f"{remothost}:{remoteport} -> {targethost}:{targetport}")
            Frpc(remothost, remoteport, targethost, targetport).run()
    def analyze_captured_packets(self):
        """
        分析数据包
        """
        for pkt in self.capture.sniff_continuously():
            try:
                proto = pkt.transport_layer  # 'TCP' or 'UDP'
                src_addr = pkt.ip.src
                dst_addr = pkt.ip.dst
                src_port = pkt[pkt.transport_layer].srcport
                dst_port = pkt[pkt.transport_layer].dstport
                length = pkt.length
                print(f'{proto} {src_addr}:{src_port} -> {dst_addr}:{dst_port}  {length} bytes')
            except AttributeError:
                # 非 IPv4 或没有传输层字段时跳过
                continue



if __name__ == "__main__":
    # 创建进程工具实例
    process_tool = PrcessTool()
    net_tool=NetTool()
    # 获取指定进程的端口信息
    process_name = "Avorion.exe"
    portsData = process_tool.get_port_by_name(process_name)
    print(portsData)
    net_tool.frp_port_list([portData['port'] for portData in portsData])